package com.haiyou.mini.programs.service.impl;


import com.haiyou.common.exception.BusinessException;
import com.haiyou.common.util.IdWorker;
import com.haiyou.common.util.ValidatorUtil;
import com.haiyou.mini.programs.config.WxMiniConfig;
import com.haiyou.mini.programs.model.PayInfo;
import com.haiyou.mini.programs.model.vo.RefundVO;
import com.haiyou.mini.programs.service.WxMiniPayService;
import com.haiyou.mini.programs.wxpay.WxConstant;
import com.haiyou.mini.programs.wxpay.WxPay;
import com.haiyou.mini.programs.wxpay.WxPayConstants;
import com.haiyou.mini.programs.wxpay.WxPayUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;

/**
 * 支付服务实现
 */
@Slf4j
@RequiredArgsConstructor
public class WxMiniPayServiceImpl implements WxMiniPayService {

    private final WxMiniConfig wxPayConfig;

    @Override
    public Map<String, String> doUnifiedOrder(PayInfo payInfo) {
        try {

            ValidatorUtil.validateEntity(payInfo);

            //统一下单接口请求参数
            Map<String, String> data = new HashMap<>();
            Map<String, String> resultMap = new HashMap();

            Integer totalPrice = payInfo.getTotalPrice().multiply(new BigDecimal(100)).intValue();

            WxPay wxpay = new WxPay(wxPayConfig);
            //生成的随机字符串
            String nonceStr = WxPayUtil.generateNonceStr();
            String spBillCreateIp = InetAddress.getLocalHost().getHostAddress();
            data.put("appid", wxPayConfig.getAppID());
            data.put("mch_id", wxPayConfig.getMchID());
            data.put("nonce_str", nonceStr);
            data.put("body", payInfo.getBody());
            data.put("out_trade_no", payInfo.getOrderNo());
            data.put("total_fee", String.valueOf(totalPrice));
            data.put("spbill_create_ip", spBillCreateIp);
            data.put("notify_url", wxPayConfig.getNotifyUrl());
            data.put("trade_type", WxConstant.TRADE_TYPE_JSAPI);
            data.put("openid", payInfo.getOpenid());
            //附加数据
            if (!StringUtils.isEmpty(payInfo.getAttach())) {
                data.put("attach", payInfo.getAttach());
            }
            log.info("下单请求参数==>{}", data);
            Map<String, String> rMap = wxpay.unifiedOrder(data);
            log.info("下单响应结果==>{}", rMap);
            String returnCode = rMap.get("return_code");
            String resultCode = rMap.get("result_code");
            if (WxPayConstants.SUCCESS.equals(returnCode) && returnCode.equals(resultCode)) {
                resultMap.put("package", "prepay_id=" + rMap.get("prepay_id"));
                resultMap.put("signType", "MD5");
                resultMap.put("nonceStr", WxPayUtil.generateNonceStr());
                //这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
                resultMap.put("timeStamp", WxPayUtil.getCurrentTimestamp() + "");
                //再次签名，这个签名用于小程序端调用wx.requesetPayment方法
                resultMap.put("appId", wxPayConfig.getAppID());
                String sign = WxPayUtil.generateSignature(resultMap, wxPayConfig.getKey());
                resultMap.put("paySign", sign);
                log.info("下单响应签名后结果==>{}", rMap);
                return resultMap;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        throw new RuntimeException("下单失败");
    }

    @Override
    public String scanOrder(PayInfo payInfo) {
        try {
            WxPay wxpay = new WxPay(wxPayConfig);
            //生成的随机字符串
            String nonce_str = WxPayUtil.generateNonceStr();
            //获取客户端的ip地址
            //获取本机的ip地址
            String spBillCreateIp = InetAddress.getLocalHost().getHostAddress();
            //支付金额，需要转成字符串类型，否则后面的签名会失败
            Integer totalPrice = payInfo.getTotalPrice().multiply(new BigDecimal(100)).intValue();
            //统一下单接口参数
            HashMap<String, String> data = new HashMap<>();
            data.put("appid", wxPayConfig.getAppID());
            data.put("mch_id", wxPayConfig.getMchID());
            data.put("nonce_str", nonce_str);
            data.put("body", payInfo.getBody());
            data.put("out_trade_no", payInfo.getOrderNo());
            data.put("total_fee", String.valueOf(totalPrice));
            data.put("spbill_create_ip", spBillCreateIp);
            data.put("trade_type", WxConstant.TRADE_TYPE_NATIVE);
            data.put("notify_url", wxPayConfig.getNotifyUrl());
            log.info("---->扫码下单接口参数={}", data);
            Map<String, String> rMap = wxpay.unifiedOrder(data);
            log.info("---->扫码下单接口返回={}", rMap);
            String return_code = rMap.get("return_code");
            String result_code = rMap.get("result_code");
            if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
                return rMap.get("code_url");
            }
        } catch (Exception e) {
            log.error("-------->扫码下单接口错误={},{}", e.getMessage(), e);
        }
        throw new BusinessException("扫码下单接口错误");
    }

    @Override
    public Map<String, String> refund(RefundVO refundVO) {
        try {
            WxPay wxpay = new WxPay(wxPayConfig);
            //生成的随机字符串
            String nonceStr = WxPayUtil.generateNonceStr();

            //初始化退款、撤销时的商户证书
            wxPayConfig.initCertFile();

            //构建参数
            Map<String, String> dataMap = new HashMap<>();
            dataMap.put("appid", wxPayConfig.getAppID());
            dataMap.put("mch_id", wxPayConfig.getMchID());
            dataMap.put("nonce_str", nonceStr);
            dataMap.put("transaction_id", refundVO.getTransaction_id());
            dataMap.put("out_refund_no", IdWorker.getId());
            dataMap.put("total_fee", refundVO.getRefund_fee());
            dataMap.put("refund_fee", refundVO.getRefund_fee());
            dataMap.put("refund_desc", refundVO.getRefund_desc());
            //生成签名
            String sign = WxPayUtil.generateSignature(dataMap, wxPayConfig.getKey());
            dataMap.put("sign", sign);

            Map<String, String> rMap = wxpay.refund(dataMap);
            log.info("---->扫码下单接口返回={}", rMap);
            String return_code = rMap.get("return_code");
            String result_code = rMap.get("result_code");
            if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
                return rMap;
            }
        } catch (Exception e) {
            log.error("-------->退款接口异常={},{}", e.getMessage(), e);
        }
        throw new BusinessException("退款接口异常");
    }


}
